package com.theory.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.theory.base.util.JwtUtils;
import com.theory.common.exception.Assert;
import com.theory.common.result.ResponseEnum;
import com.theory.common.util.MD5;
import com.theory.core.mapper.UserAccountMapper;
import com.theory.core.mapper.UserInfoMapper;
import com.theory.core.mapper.UserLoginRecordMapper;
import com.theory.core.pojo.entity.UserAccount;
import com.theory.core.pojo.entity.UserInfo;
import com.theory.core.pojo.entity.UserLoginRecord;
import com.theory.core.pojo.query.UserInfoQuery;
import com.theory.core.pojo.vo.LoginVO;
import com.theory.core.pojo.vo.RegisterVO;
import com.theory.core.pojo.vo.UserInfoVO;
import com.theory.core.service.UserInfoService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * <p>
 * 用户基本信息 服务实现类
 * </p>
 *
 * @author Theory
 * @since 2021-09-24
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> implements UserInfoService {


    @Resource
    private UserAccountMapper userAccountMapper;

    @Resource
    private UserLoginRecordMapper userLoginRecordMapper;


    /**
     * 实现用户注册功能
     * @param registerVO http://localhost:3000/register 页面的表单对象
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void register(RegisterVO registerVO) {

        // 判断用户是否被注册
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",registerVO.getMobile());
        Integer count = baseMapper.selectCount(queryWrapper);
        Assert.isTrue(count == 0, ResponseEnum.MOBILE_EXIST_ERROR);

        // 插入用户基本信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserType(registerVO.getUserType());
        userInfo.setNickName(registerVO.getMobile());
        userInfo.setName(registerVO.getMobile());
        userInfo.setMobile(registerVO.getMobile());
        userInfo.setPassword(MD5.encrypt(registerVO.getPassword()));
        userInfo.setStatus(UserInfo.STATUS_NORMAL); //设置状态为正常
        // 设置一张静态资源服务器上的头像图片
        userInfo.setHeadImg("https://codetheory-srb.oss-cn-shenzhen.aliyuncs.com/avatar/1.png");
        baseMapper.insert(userInfo);

        // 创建会员账户
        UserAccount userAccount = new UserAccount();
        // 这里为什么能拿到id，这里有点像数据双向绑定一样，当插入成功的时候，会把id给填充上，所以我们这里能get到id
        userAccount.setUserId(userInfo.getId());
        userAccountMapper.insert(userAccount);
    }

    /**
     * 登录的方法，这里面涉及到三个对象，一个是表单的对象，一个是数据库查到的用户对象，然后将用户对象封装成UserInfoVo
     * @param loginVO 登录的表单
     * @param ip 获取的ip
     * @return 前台显示需要的信息封装成的对象，其实和UserInfo产不多，只不过多了个token
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public UserInfoVO login(LoginVO loginVO, String ip) {
        String mobile = loginVO.getMobile();
        String password = loginVO.getPassword();
        Integer userType = loginVO.getUserType();

        // 获取会员
        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",mobile);
        // 这个user_type 是指出借人/借款人
        queryWrapper.eq("user_type",userType);
        UserInfo userInfo = baseMapper.selectOne(queryWrapper);

        // 用户不存在
        Assert.notNull(userInfo, ResponseEnum.LOGIN_MOBILE_ERROR);

        // 校验密码
        Assert.equals(MD5.encrypt(password), userInfo.getPassword(), ResponseEnum.LOGIN_PASSWORD_ERROR);

        // 用户是否被禁用
        Assert.equals(userInfo.getStatus(), UserInfo.STATUS_NORMAL, ResponseEnum.LOGIN_LOKED_ERROR);

        // 记录登录日志
        UserLoginRecord userLoginRecord = new UserLoginRecord();
        userLoginRecord.setUserId(userInfo.getId());
        userLoginRecord.setIp(ip);
        userLoginRecordMapper.insert(userLoginRecord);

        // 生成token
        String token = JwtUtils.createToken(userInfo.getId(), userInfo.getName());
        // 填充数据
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setToken(token);
        userInfoVO.setName(userInfo.getName());
        userInfoVO.setNickName(userInfo.getNickName());
        userInfoVO.setHeadImg(userInfo.getHeadImg());
        userInfoVO.setMobile(userInfo.getMobile());
        userInfoVO.setUserType(userInfo.getUserType());

        return userInfoVO;
    }

    /**
     * 分页查询的方法
     * @param pageParam 由page和limit组装的page对象
     * @param userInfoQuery 查询条件
     * @return IPage
     */
    @Override
    public IPage<UserInfo> listPage(Page<UserInfo> pageParam, UserInfoQuery userInfoQuery) {
        String mobile = userInfoQuery.getMobile();
        Integer status = userInfoQuery.getStatus();
        Integer userType = userInfoQuery.getUserType();

        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();

        if (userInfoQuery == null) {
            return baseMapper.selectPage(pageParam, null);
        }

        // 组装条件，不满足前面的条件时，不会进行拼接
        queryWrapper
                .eq(StringUtils.isNotBlank(mobile), "mobile", mobile)
                .eq(status != null, "status", status)
                .eq(userType != null, "user_type", userType);


        return baseMapper.selectPage(pageParam, queryWrapper);
    }

    @Override
    public void lock(Long id, Integer status) {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(id);
        userInfo.setStatus(status);

        baseMapper.updateById(userInfo);

        // 还有一种方法，下面this是IService，即调用者，不过这样写会多执行一次查询的sql
//        UserInfo userInfo = this.getById(id);
//        userInfo.setId(id);
//        userInfo.setStatus(status);
//        baseMapper.updateById(userInfo);
    }

    /**
     * 校验手机号码是否存在
     * @param mobile 手机号
     * @return true为以存在,false为不存在
     */
    @Override
    public boolean checkMobile(String mobile) {

        QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile",mobile);
        Integer count = baseMapper.selectCount(queryWrapper);
        return count > 0;
    }
}
